home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Direct3D / ShadowMap / shadowmap.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-28  |  44.0 KB  |  972 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: ShadowMap.cpp
  3. //
  4. // Starting point for new Direct3D applications
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //--------------------------------------------------------------------------------------
  8. #include "dxstdafx.h"
  9. #include "dxutmesh.h"
  10. #include "resource.h"
  11.  
  12. //#define DEBUG_VS   // Uncomment this line to debug vertex shaders 
  13. //#define DEBUG_PS   // Uncomment this line to debug pixel shaders 
  14.  
  15.  
  16. #define SHADOWMAP_SIZE 512
  17.  
  18. #define HELPTEXTCOLOR D3DXCOLOR( 0.0f, 1.0f, 0.3f, 1.0f )
  19.  
  20. LPCTSTR g_aszMeshFile[] =
  21. {
  22.     L"room.x",
  23.     L"airplane\\airplane 2.x",
  24.     L"misc\\car.x",
  25.     L"misc\\sphere.x",
  26.     L"UI\\arrow.x",
  27.     L"UI\\arrow.x",
  28.     L"UI\\arrow.x",
  29.     L"UI\\arrow.x",
  30.     L"UI\\arrow.x",
  31.     L"UI\\arrow.x",
  32.     L"UI\\arrow.x",
  33.     L"UI\\arrow.x",
  34.     L"ring.x",
  35.     L"ring.x",
  36. };
  37.  
  38. #define NUM_OBJ (sizeof(g_aszMeshFile)/sizeof(g_aszMeshFile[0]))
  39.  
  40. D3DXMATRIXA16 g_amInitObjWorld[NUM_OBJ] =
  41. {
  42.     D3DXMATRIXA16( 3.5f, 0.0f, 0.0f, 0.0f, 0.0f, 3.0f, 0.0f, 0.0f, 0.0f, 0.0f, 3.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f ),
  43.     D3DXMATRIXA16( 0.43301f, 0.25f, 0.0f, 0.0f, -0.25f, 0.43301f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 5.0f, 1.33975f, 0.0f, 1.0f ),
  44.     D3DXMATRIXA16( 0.8f, 0.0f, 0.0f, 0.0f, 0.0f, 0.8f, 0.0f, 0.0f, 0.0f, 0.0f, 0.8f, 0.0f, -14.5f, -7.1f, 0.0f, 1.0f ),
  45.     D3DXMATRIXA16( 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.0f, -7.0f, 0.0f, 1.0f ),
  46.     D3DXMATRIXA16( 5.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 5.5f, 0.0f, 0.0f, -9.0f, 0.0f, 0.0f, 5.0f, 0.2f, 5.0f, 1.0f ),
  47.     D3DXMATRIXA16( 5.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 5.5f, 0.0f, 0.0f, -9.0f, 0.0f, 0.0f, 5.0f, 0.2f, -5.0f, 1.0f ),
  48.     D3DXMATRIXA16( 5.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 5.5f, 0.0f, 0.0f, -9.0f, 0.0f, 0.0f, -5.0f, 0.2f, 5.0f, 1.0f ),
  49.     D3DXMATRIXA16( 5.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 5.5f, 0.0f, 0.0f, -9.0f, 0.0f, 0.0f, -5.0f, 0.2f, -5.0f, 1.0f ),
  50.     D3DXMATRIXA16( 5.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 5.5f, 0.0f, 0.0f, -9.0f, 0.0f, 0.0f, 14.0f, 0.2f, 14.0f, 1.0f ),
  51.     D3DXMATRIXA16( 5.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 5.5f, 0.0f, 0.0f, -9.0f, 0.0f, 0.0f, 14.0f, 0.2f, -14.0f, 1.0f ),
  52.     D3DXMATRIXA16( 5.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 5.5f, 0.0f, 0.0f, -9.0f, 0.0f, 0.0f, -14.0f, 0.2f, 14.0f, 1.0f ),
  53.     D3DXMATRIXA16( 5.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 5.5f, 0.0f, 0.0f, -9.0f, 0.0f, 0.0f, -14.0f, 0.2f, -14.0f, 1.0f ),
  54.     D3DXMATRIXA16( 0.9f, 0.0f, 0.0f, 0.0f, 0.0f, 0.9f, 0.0f, 0.0f, 0.0f, 0.0f, 0.9f, 0.0f, -14.5f, -9.0f, 0.0f, 1.0f ),
  55.     D3DXMATRIXA16( 0.9f, 0.0f, 0.0f, 0.0f, 0.0f, 0.9f, 0.0f, 0.0f, 0.0f, 0.0f, 0.9f, 0.0f, 14.5f, -9.0f, 0.0f, 1.0f ),
  56. };
  57.  
  58.  
  59. D3DVERTEXELEMENT9 g_aVertDecl[] =
  60. {
  61.     { 0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
  62.     { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0 },
  63.     { 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
  64.     D3DDECL_END()
  65. };
  66.  
  67.  
  68. //-----------------------------------------------------------------------------
  69. // Name: class CObj
  70. // Desc: Encapsulates a mesh object in the scene by grouping its world matrix
  71. //       with the mesh.
  72. //-----------------------------------------------------------------------------
  73. struct CObj
  74. {
  75.     CDXUTMesh m_Mesh;
  76.     D3DXMATRIXA16 m_mWorld;
  77. };
  78.  
  79.  
  80.  
  81.  
  82. //-----------------------------------------------------------------------------
  83. // Name: class CViewCamera
  84. // Desc: A camera class derived from CFirstPersonCamera.  The arrow keys and
  85. //       numpad keys are disabled for this type of camera.
  86. //-----------------------------------------------------------------------------
  87. class CViewCamera : public CFirstPersonCamera
  88. {
  89. protected:
  90.     virtual D3DUtil_CameraKeys MapKey( UINT nKey )
  91.     {
  92.         // Provide custom mapping here.
  93.         // Same as default mapping but disable arrow keys.
  94.         switch( nKey )
  95.         {
  96.             case 'A':      return CAM_STRAFE_LEFT;
  97.             case 'D':      return CAM_STRAFE_RIGHT;
  98.             case 'W':      return CAM_MOVE_FORWARD;
  99.             case 'S':      return CAM_MOVE_BACKWARD;
  100.             case 'Q':      return CAM_MOVE_DOWN;
  101.             case 'E':      return CAM_MOVE_UP;
  102.  
  103.             case VK_HOME:   return CAM_RESET;
  104.         }
  105.  
  106.         return CAM_UNKNOWN;
  107.     }
  108. };
  109.  
  110.  
  111.  
  112.  
  113. //-----------------------------------------------------------------------------
  114. // Name: class CLightCamera
  115. // Desc: A camera class derived from CFirstPersonCamera.  The letter keys
  116. //       are disabled for this type of camera.  This class is intended for use
  117. //       by the spot light.
  118. //-----------------------------------------------------------------------------
  119. class CLightCamera : public CFirstPersonCamera
  120. {
  121. protected:
  122.     virtual D3DUtil_CameraKeys MapKey( UINT nKey )
  123.     {
  124.         // Provide custom mapping here.
  125.         // Same as default mapping but disable arrow keys.
  126.         switch( nKey )
  127.         {
  128.             case VK_LEFT:  return CAM_STRAFE_LEFT;
  129.             case VK_RIGHT: return CAM_STRAFE_RIGHT;
  130.             case VK_UP:    return CAM_MOVE_FORWARD;
  131.             case VK_DOWN:  return CAM_MOVE_BACKWARD;
  132.             case VK_PRIOR: return CAM_MOVE_UP;        // pgup
  133.             case VK_NEXT:  return CAM_MOVE_DOWN;      // pgdn
  134.  
  135.             case VK_NUMPAD4: return CAM_STRAFE_LEFT;
  136.             case VK_NUMPAD6: return CAM_STRAFE_RIGHT;
  137.             case VK_NUMPAD8: return CAM_MOVE_FORWARD;
  138.             case VK_NUMPAD2: return CAM_MOVE_BACKWARD;
  139.             case VK_NUMPAD9: return CAM_MOVE_UP;        
  140.             case VK_NUMPAD3: return CAM_MOVE_DOWN;      
  141.  
  142.             case VK_HOME:   return CAM_RESET;
  143.         }
  144.  
  145.         return CAM_UNKNOWN;
  146.     }
  147. };
  148.  
  149.  
  150. //--------------------------------------------------------------------------------------
  151. // Global variables
  152. //--------------------------------------------------------------------------------------
  153. ID3DXFont*              g_pFont = NULL;         // Font for drawing text
  154. ID3DXFont*              g_pFontSmall = NULL;    // Font for drawing text
  155. ID3DXSprite*            g_pTextSprite = NULL;   // Sprite for batching draw text calls
  156. ID3DXEffect*            g_pEffect = NULL;       // D3DX effect interface
  157. bool                    g_bShowHelp = true;     // If true, it renders the UI control text
  158. CDXUTDialog             g_HUD;                  // dialog for standard controls
  159. CFirstPersonCamera      g_VCamera;              // View camera
  160. CFirstPersonCamera      g_LCamera;              // Camera obj to help adjust light
  161. CObj                    g_Obj[NUM_OBJ];         // Scene object meshes
  162. LPDIRECT3DVERTEXDECLARATION9 g_pVertDecl = NULL;// Vertex decl for the sample
  163. LPDIRECT3DTEXTURE9      g_pTexDef = NULL;       // Default texture for objects
  164. D3DLIGHT9               g_Light;                // The spot light in the scene
  165. CDXUTMesh               g_LightMesh;
  166. LPDIRECT3DTEXTURE9      g_pShadowMap = NULL;    // Texture to which the shadow map is rendered
  167. LPDIRECT3DSURFACE9      g_pDSShadow = NULL;     // Depth-stencil buffer for rendering to shadow map
  168. float                   g_fLightFov;            // FOV of the spot light (in radian)
  169. D3DXMATRIXA16           g_mShadowProj;          // Projection matrix for shadow map
  170.  
  171. bool                    g_bRightMouseDown = false;// Indicates whether right mouse button is held
  172. bool                    g_bCameraPerspective    // Indicates whether we should render view from
  173.                           = true;               // the camera's or the light's perspective
  174. bool                    g_bFreeLight = true;    // Whether the light is freely moveable.
  175.  
  176.  
  177. //--------------------------------------------------------------------------------------
  178. // UI control IDs
  179. //--------------------------------------------------------------------------------------
  180. #define IDC_TOGGLEFULLSCREEN 1
  181. #define IDC_TOGGLEREF        3
  182. #define IDC_CHANGEDEVICE     4
  183. #define IDC_CHECKBOX         5
  184. #define IDC_LIGHTPERSPECTIVE 6
  185. #define IDC_ATTACHLIGHTTOCAR 7
  186.  
  187.  
  188.  
  189. //--------------------------------------------------------------------------------------
  190. // Forward declarations 
  191. //--------------------------------------------------------------------------------------
  192. void             InitializeDialogs();
  193. bool    CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed );
  194. void    CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps );
  195. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  196. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  197. void    CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  198. void    CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  199. void             RenderText();
  200. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing );
  201. void    CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown  );
  202. void    CALLBACK MouseProc( bool bLeftButtonDown, bool bRightButtonDown, bool bMiddleButtonDown, bool bSideButton1Down, bool bSideButton2Down, int nMouseWheelDelta, int xPos, int yPos );
  203. void    CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl );
  204. void    CALLBACK OnLostDevice();
  205. void    CALLBACK OnDestroyDevice();
  206. void             RenderScene( IDirect3DDevice9* pd3dDevice, bool bRenderShadow, float fElapsedTime, const D3DXMATRIX *pmView, const D3DXMATRIX *pmProj );
  207.  
  208.  
  209. //--------------------------------------------------------------------------------------
  210. // Entry point to the program. Initializes everything and goes into a message processing 
  211. // loop. Idle time is used to render the scene.
  212. //--------------------------------------------------------------------------------------
  213. INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
  214. {
  215.     // Initialize the camera
  216.     g_VCamera.SetScalers( 0.01f, 15.0f );
  217.     g_LCamera.SetScalers( 0.01f, 8.0f );
  218.     g_VCamera.SetRotateButtons( true, false, false );
  219.     g_LCamera.SetRotateButtons( false, false, true );
  220.  
  221.     // Set up the view parameters for the camera
  222.     D3DXVECTOR3 vFromPt   = D3DXVECTOR3( 0.0f, 5.0f, -18.0f );
  223.     D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.0f, -1.0f, 0.0f );
  224.     g_VCamera.SetViewParams( &vFromPt, &vLookatPt );
  225.  
  226.     vFromPt = D3DXVECTOR3( 0.0f, 0.0f, -12.0f );
  227.     vLookatPt = D3DXVECTOR3( 0.0f, -2.0f, 1.0f );
  228.     g_LCamera.SetViewParams( &vFromPt, &vLookatPt );
  229.  
  230.     // Initialize the spot light
  231.     g_fLightFov = D3DX_PI / 2.0f;
  232.  
  233.     g_Light.Diffuse.r = 1.0f;
  234.     g_Light.Diffuse.g = 1.0f;
  235.     g_Light.Diffuse.b = 1.0f;
  236.     g_Light.Diffuse.a = 1.0f;
  237.     g_Light.Position = D3DXVECTOR3( -8.0f, -8.0f, 0.0f );
  238.     g_Light.Direction = D3DXVECTOR3( 1.0f, -1.0f, 0.0f );
  239.     D3DXVec3Normalize( (D3DXVECTOR3*)&g_Light.Direction, (D3DXVECTOR3*)&g_Light.Direction );
  240.     g_Light.Range = 10.0f;
  241.     g_Light.Theta = g_fLightFov / 2.0f;
  242.     g_Light.Phi = g_fLightFov / 2.0f;
  243.  
  244.     // Set the callback functions. These functions allow the sample framework to notify
  245.     // the application about device changes, user input, and windows messages.  The 
  246.     // callbacks are optional so you need only set callbacks for events you're interested 
  247.     // in. However, if you don't handle the device reset/lost callbacks then the sample 
  248.     // framework won't be able to reset your device since the application must first 
  249.     // release all device resources before resetting.  Likewise, if you don't handle the 
  250.     // device created/destroyed callbacks then the sample framework won't be able to 
  251.     // recreate your device resources.
  252.     DXUTSetCallbackDeviceCreated( OnCreateDevice );
  253.     DXUTSetCallbackDeviceReset( OnResetDevice );
  254.     DXUTSetCallbackDeviceLost( OnLostDevice );
  255.     DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
  256.     DXUTSetCallbackMsgProc( MsgProc );
  257.     DXUTSetCallbackKeyboard( KeyboardProc );
  258.     DXUTSetCallbackMouse( MouseProc );
  259.     DXUTSetCallbackFrameRender( OnFrameRender );
  260.     DXUTSetCallbackFrameMove( OnFrameMove );
  261.  
  262.     InitializeDialogs();
  263.  
  264.     // Show the cursor and clip it when in full screen
  265.     DXUTSetCursorSettings( true, true );
  266.  
  267.     // Initialize the sample framework and create the desired Win32 window and Direct3D 
  268.     // device for the application. Calling each of these functions is optional, but they
  269.     // allow you to set several options which control the behavior of the framework.
  270.     DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  271.     DXUTCreateWindow( L"ShadowMap" );
  272.     DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );
  273.  
  274.     // Pass control to the sample framework for handling the message pump and 
  275.     // dispatching render calls. The sample framework will call your FrameMove 
  276.     // and FrameRender callback when there is idle time between handling window messages.
  277.     DXUTMainLoop();
  278.  
  279.     // Perform any application-level cleanup here. Direct3D device resources are released within the
  280.     // appropriate callback functions and therefore don't require any cleanup code here.
  281.  
  282.     return DXUTGetExitCode();
  283. }
  284.  
  285.  
  286. //--------------------------------------------------------------------------------------
  287. // Sets up the dialogs
  288. //--------------------------------------------------------------------------------------
  289. void InitializeDialogs()
  290. {
  291.     g_HUD.SetCallback( OnGUIEvent ); int iY = 10; 
  292.     g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
  293.     g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22 );
  294.     g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22 );
  295.     g_HUD.AddCheckBox( IDC_CHECKBOX, L"Display help text", 35, iY += 24, 125, 22, true, VK_F1 );
  296.     g_HUD.AddCheckBox( IDC_LIGHTPERSPECTIVE, L"View from light's perspective", 0, iY += 24, 160, 22, false, L'V' );
  297.     g_HUD.AddCheckBox( IDC_ATTACHLIGHTTOCAR, L"Attach light to car", 0, iY += 24, 160, 22, false, L'F' );
  298. }
  299.  
  300.  
  301. //--------------------------------------------------------------------------------------
  302. // Called during device initialization, this code checks the device for some 
  303. // minimum set of capabilities, and rejects those that don't pass by returning false.
  304. //--------------------------------------------------------------------------------------
  305. bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, 
  306.                                   D3DFORMAT BackBufferFormat, bool bWindowed )
  307. {
  308.     // Skip backbuffer formats that don't support alpha blending
  309.     IDirect3D9* pD3D = DXUTGetD3DObject(); 
  310.     if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
  311.                     AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, 
  312.                     D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
  313.         return false;
  314.  
  315.     // Must support pixel shader 2.0
  316.     if( pCaps->PixelShaderVersion < D3DPS_VERSION( 2, 0 ) )
  317.         return false;
  318.  
  319.     // need to support D3DFMT_R32F render target
  320.     if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
  321.                     AdapterFormat, D3DUSAGE_RENDERTARGET, 
  322.                     D3DRTYPE_CUBETEXTURE, D3DFMT_R32F ) ) )
  323.         return false;
  324.  
  325.     // need to support D3DFMT_A8R8G8B8 render target
  326.     if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
  327.                     AdapterFormat, D3DUSAGE_RENDERTARGET, 
  328.                     D3DRTYPE_CUBETEXTURE, D3DFMT_A8R8G8B8 ) ) )
  329.         return false;
  330.  
  331.     return true;
  332. }
  333.  
  334.  
  335. //--------------------------------------------------------------------------------------
  336. // This callback function is called immediately before a device is created to allow the 
  337. // application to modify the device settings. The supplied pDeviceSettings parameter 
  338. // contains the settings that the framework has selected for the new device, and the 
  339. // application can make any desired changes directly to this structure.  Note however that 
  340. // the sample framework will not correct invalid device settings so care must be taken 
  341. // to return valid device settings, otherwise IDirect3D9::CreateDevice() will fail.  
  342. //--------------------------------------------------------------------------------------
  343. void CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps )
  344. {
  345.     // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
  346.     // then switch to SWVP.
  347.     if( (pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||
  348.          pCaps->VertexShaderVersion < D3DVS_VERSION(1,1) )
  349.     {
  350.         pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  351.     }
  352.     else
  353.     {
  354.         pDeviceSettings->BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  355.     }
  356.  
  357.     // This application is designed to work on a pure device by not using 
  358.     // IDirect3D9::Get*() methods, so create a pure device if supported and using HWVP.
  359.     if ((pCaps->DevCaps & D3DDEVCAPS_PUREDEVICE) != 0 && 
  360.         (pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0 )
  361.         pDeviceSettings->BehaviorFlags |= D3DCREATE_PUREDEVICE;
  362.  
  363.     // Debugging vertex shaders requires either REF or software vertex processing 
  364.     // and debugging pixel shaders requires REF.  
  365. #ifdef DEBUG_VS
  366.     if( pDeviceSettings->DeviceType != D3DDEVTYPE_REF )
  367.     {
  368.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
  369.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;                            
  370.         pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  371.     }
  372. #endif
  373. #ifdef DEBUG_PS
  374.     pDeviceSettings->DeviceType = D3DDEVTYPE_REF;
  375. #endif
  376. }
  377.  
  378.  
  379. //--------------------------------------------------------------------------------------
  380. // This callback function will be called immediately after the Direct3D device has been 
  381. // created, which will happen during application initialization and windowed/full screen 
  382. // toggles. This is the best location to create D3DPOOL_MANAGED resources since these 
  383. // resources need to be reloaded whenever the device is destroyed. Resources created  
  384. // here should be released in the OnDestroyDevice callback. 
  385. //--------------------------------------------------------------------------------------
  386. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  387. {
  388.     HRESULT hr;
  389.  
  390.     // Initialize the font
  391.     V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, 
  392.                          OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, 
  393.                          L"Arial", &g_pFont ) );
  394.     V_RETURN( D3DXCreateFont( pd3dDevice, 12, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, 
  395.                          OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, 
  396.                          L"Arial", &g_pFontSmall ) );
  397.  
  398.     // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  399.     // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  400.     // processing, and debugging pixel shaders requires REF.  The 
  401.     // D3DXSHADER_FORCE_*_SOFTWARE_NOOPT flag improves the debug experience in the 
  402.     // shader debugger.  It enables source level debugging, prevents instruction 
  403.     // reordering, prevents dead code elimination, and forces the compiler to compile 
  404.     // against the next higher available software target, which ensures that the 
  405.     // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  406.     // flags will cause slower rendering since the shaders will be unoptimized and 
  407.     // forced into software.  See the DirectX documentation for more information about 
  408.     // using the shader debugger.
  409.     DWORD dwShaderFlags = 0;
  410.     #ifdef DEBUG_VS
  411.         dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
  412.     #endif
  413.     #ifdef DEBUG_PS
  414.         dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
  415.     #endif
  416.  
  417.     // Read the D3DX effect file
  418.     WCHAR str[MAX_PATH];
  419.     V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"ShadowMap.fx" ) );
  420.  
  421.     // If this fails, there should be debug output as to 
  422.     // they the .fx file failed to compile
  423.     V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, str, NULL, NULL, dwShaderFlags, 
  424.                                         NULL, &g_pEffect, NULL ) );
  425.  
  426.     // Create vertex declaration
  427.     V_RETURN( pd3dDevice->CreateVertexDeclaration( g_aVertDecl, &g_pVertDecl ) );
  428.  
  429.     // Initialize the meshes
  430.     for( int i = 0; i < NUM_OBJ; ++i )
  431.     {
  432.         V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, g_aszMeshFile[i] ) );
  433.         if( FAILED( g_Obj[i].m_Mesh.Create( pd3dDevice, str ) ) )
  434.             return DXUTERR_MEDIANOTFOUND;
  435.         V_RETURN( g_Obj[i].m_Mesh.SetVertexDecl( pd3dDevice, g_aVertDecl ) );
  436.         g_Obj[i].m_mWorld = g_amInitObjWorld[i];
  437.     }
  438.  
  439.     // Initialize the light mesh
  440.     V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"spotlight.x" ) );
  441.     if( FAILED( g_LightMesh.Create( pd3dDevice, str ) ) )
  442.         return DXUTERR_MEDIANOTFOUND;
  443.     V_RETURN( g_LightMesh.SetVertexDecl( pd3dDevice, g_aVertDecl ) );
  444.  
  445.     // World transform to identity
  446.     D3DXMATRIXA16 mIdent;
  447.     D3DXMatrixIdentity( &mIdent );
  448.     V_RETURN( pd3dDevice->SetTransform( D3DTS_WORLD, &mIdent ) );
  449.  
  450.     return S_OK;
  451. }
  452.  
  453.  
  454. //--------------------------------------------------------------------------------------
  455. // This callback function will be called immediately after the Direct3D device has been 
  456. // reset, which will happen after a lost device scenario. This is the best location to 
  457. // create D3DPOOL_DEFAULT resources since these resources need to be reloaded whenever 
  458. // the device is lost. Resources created here should be released in the OnLostDevice 
  459. // callback. 
  460. //--------------------------------------------------------------------------------------
  461. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, 
  462.                                 const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  463. {
  464.     HRESULT hr;
  465.  
  466.     if( g_pFont )
  467.         V_RETURN( g_pFont->OnResetDevice() );
  468.     if( g_pFontSmall )
  469.         V_RETURN( g_pFontSmall->OnResetDevice() );
  470.     if( g_pEffect )
  471.         V_RETURN( g_pEffect->OnResetDevice() );
  472.  
  473.     // Create a sprite to help batch calls when drawing many lines of text
  474.     V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pTextSprite ) );
  475.  
  476.     // Setup the camera's projection parameters
  477.     float fAspectRatio = pBackBufferSurfaceDesc->Width / (FLOAT)pBackBufferSurfaceDesc->Height;
  478.     g_VCamera.SetProjParams( D3DX_PI/4, fAspectRatio, 0.1f, 100.0f );
  479.     g_LCamera.SetProjParams( D3DX_PI/4, fAspectRatio, 0.1f, 100.0f );
  480.  
  481.     // Create the default texture (used when a triangle does not use a texture)
  482.     V_RETURN( pd3dDevice->CreateTexture( 1, 1, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_pTexDef, NULL ) );
  483.     D3DLOCKED_RECT lr;
  484.     V_RETURN( g_pTexDef->LockRect( 0, &lr, NULL, 0 ) );
  485.     *(LPDWORD)lr.pBits = D3DCOLOR_RGBA( 255, 255, 255, 255 );
  486.     V_RETURN( g_pTexDef->UnlockRect( 0 ) );
  487.  
  488.     // Restore the scene objects
  489.     for( int i = 0; i < NUM_OBJ; ++i )
  490.         V_RETURN( g_Obj[i].m_Mesh.RestoreDeviceObjects( pd3dDevice ) );
  491.     V_RETURN( g_LightMesh.RestoreDeviceObjects( pd3dDevice ) );
  492.  
  493.     // Restore the effect variables
  494.     V_RETURN( g_pEffect->SetVector( "g_vLightDiffuse", (D3DXVECTOR4 *)&g_Light.Diffuse ) );
  495.     V_RETURN( g_pEffect->SetFloat( "g_fCosTheta", cosf( g_Light.Theta ) ) );
  496.  
  497.     // Create the shadow map texture
  498.     V_RETURN( pd3dDevice->CreateTexture( SHADOWMAP_SIZE, SHADOWMAP_SIZE,
  499.                                          1, D3DUSAGE_RENDERTARGET,
  500.                                          D3DFMT_R32F,
  501.                                          D3DPOOL_DEFAULT,
  502.                                          &g_pShadowMap,
  503.                                          NULL ) );
  504.  
  505.     // Create the depth-stencil buffer to be used with the shadow map
  506.     // We do this to ensure that the depth-stencil buffer is large
  507.     // enough and has correct multisample type/quality when rendering
  508.     // the shadow map.  The default depth-stencil buffer created during
  509.     // device creation will not be large enough if the user resizes the
  510.     // window to a very small size.  Furthermore, if the device is created
  511.     // with multisampling, the default depth-stencil buffer will not
  512.     // work with the shadow map texture because texture render targets
  513.     // do not support multisample.
  514.     DXUTDeviceSettings d3dSettings = DXUTGetDeviceSettings();
  515.     V_RETURN( pd3dDevice->CreateDepthStencilSurface( SHADOWMAP_SIZE,
  516.                                                      SHADOWMAP_SIZE,
  517.                                                      d3dSettings.pp.AutoDepthStencilFormat,
  518.                                                      D3DMULTISAMPLE_NONE,
  519.                                                      0,
  520.                                                      TRUE,
  521.                                                      &g_pDSShadow,
  522.                                                      NULL ) );
  523.  
  524.     // Initialize the shadow projection matrix
  525.     D3DXMatrixPerspectiveFovLH( &g_mShadowProj, g_fLightFov, 1, 0.01f, 100.0f);
  526.  
  527.     g_HUD.SetLocation( pBackBufferSurfaceDesc->Width-170, 0 );
  528.     g_HUD.SetSize( 170, pBackBufferSurfaceDesc->Height );
  529.     CDXUTControl *pControl = g_HUD.GetControl( IDC_LIGHTPERSPECTIVE );
  530.     if( pControl )
  531.         pControl->SetLocation( 0, pBackBufferSurfaceDesc->Height - 50 );
  532.     pControl = g_HUD.GetControl( IDC_ATTACHLIGHTTOCAR );
  533.     if( pControl )
  534.         pControl->SetLocation( 0, pBackBufferSurfaceDesc->Height - 25 );
  535.     return S_OK;
  536. }
  537.  
  538.  
  539. //--------------------------------------------------------------------------------------
  540. // This callback function will be called once at the beginning of every frame. This is the
  541. // best location for your application to handle updates to the scene, but is not 
  542. // intended to contain actual rendering calls, which should instead be placed in the 
  543. // OnFrameRender callback.  
  544. //--------------------------------------------------------------------------------------
  545. void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  546. {
  547.     // Update the camera's position based on user input 
  548.     g_VCamera.FrameMove( fElapsedTime );
  549.     g_LCamera.FrameMove( fElapsedTime );
  550.  
  551.     // Animate the plane, car and sphere meshes
  552.     D3DXMATRIXA16 m;
  553.  
  554.     D3DXMatrixRotationY( &m, D3DX_PI * fElapsedTime / 4.0f );
  555.     D3DXMatrixMultiply( &g_Obj[1].m_mWorld, &g_Obj[1].m_mWorld, &m );
  556.     D3DXMatrixRotationY( &m, -D3DX_PI * fElapsedTime / 4.0f );
  557.     D3DXMatrixMultiply( &g_Obj[2].m_mWorld, &g_Obj[2].m_mWorld, &m );
  558.     D3DXVECTOR3 vR( 0.1f, 1.0f, -0.2f );
  559.     D3DXMatrixRotationAxis( &m, &vR, -D3DX_PI * fElapsedTime / 6.0f );
  560.     D3DXMatrixMultiply( &g_Obj[3].m_mWorld, &m, &g_Obj[3].m_mWorld );
  561. }
  562.  
  563.  
  564. //--------------------------------------------------------------------------------------
  565. // Renders the scene onto the current render target using the current
  566. // technique in the effect.
  567. //--------------------------------------------------------------------------------------
  568. void RenderScene( IDirect3DDevice9* pd3dDevice, bool bRenderShadow, float fElapsedTime, const D3DXMATRIX *pmView, const D3DXMATRIX *pmProj )
  569. {
  570.     HRESULT hr;
  571.  
  572.     // Set the projection matrix
  573.     V( g_pEffect->SetMatrix( "g_mProj", pmProj ) );
  574.  
  575.     // Update the light parameters in the effect
  576.     if( g_bFreeLight )
  577.     {
  578.         // Freely moveable light. Get light parameter
  579.         // from the light camera.
  580.         D3DXVECTOR3 v = *g_LCamera.GetEyePt();
  581.         D3DXVECTOR4 v4;
  582.         D3DXVec3Transform( &v4, &v, pmView );
  583.         V( g_pEffect->SetVector( "g_vLightPos", &v4 ) );
  584.         *(D3DXVECTOR3*)&v4 = *g_LCamera.GetWorldAhead();
  585.         v4.w = 0.0f;  // Set w 0 so that the translation part doesn't come to play
  586.         D3DXVec4Transform( &v4, &v4, pmView );  // Direction in view space
  587.         D3DXVec3Normalize( (D3DXVECTOR3*)&v4, (D3DXVECTOR3*)&v4 );
  588.         V( g_pEffect->SetVector( "g_vLightDir", &v4 ) );
  589.     } else
  590.     {
  591.         // Light attached to car.  Get the car's world position and direction.
  592.         D3DXMATRIXA16 m = g_Obj[2].m_mWorld;
  593.         D3DXVECTOR3 v( m._41, m._42, m._43 );
  594.         D3DXVECTOR4 vPos;
  595.         D3DXVec3Transform( &vPos, &v, pmView );
  596.         D3DXVECTOR4 v4( 0.0f, 0.0f, -1.0f, 1.0f );  // In object space, car is facing -Z
  597.         m._41 = m._42 = m._43 = 0.0f;  // Remove the translation
  598.         D3DXVec4Transform( &v4, &v4, &m );  // Obtain direction in world space
  599.         v4.w = 0.0f;  // Set w 0 so that the translation part doesn't come to play
  600.         D3DXVec4Transform( &v4, &v4, pmView );  // Direction in view space
  601.         D3DXVec3Normalize( (D3DXVECTOR3*)&v4, (D3DXVECTOR3*)&v4 );
  602.         V( g_pEffect->SetVector( "g_vLightDir", &v4 ) );
  603.         vPos += v4 * 4.0f;  // Offset the center by 3 so that it's closer to the headlight.
  604.         V( g_pEffect->SetVector( "g_vLightPos", &vPos ) );
  605.     }
  606.  
  607.     // Clear the render buffers
  608.     V( pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
  609.                           0x000000ff, 1.0f, 0L ) );
  610.  
  611.     if( bRenderShadow )
  612.         V( g_pEffect->SetTechnique( "RenderShadow" ) );
  613.  
  614.     // Begin the scene
  615.     if( SUCCEEDED( pd3dDevice->BeginScene() ) )
  616.     {
  617.         if( !bRenderShadow )
  618.             V( g_pEffect->SetTechnique( "RenderScene" ) );
  619.  
  620.         // Render the objects
  621.         for( int obj = 0; obj < NUM_OBJ; ++obj )
  622.         {
  623.             D3DXMATRIXA16 mWorldView = g_Obj[obj].m_mWorld;
  624.             D3DXMatrixMultiply( &mWorldView, &mWorldView, pmView );
  625.             V( g_pEffect->SetMatrix( "g_mWorldView", &mWorldView ) );
  626.  
  627.             LPD3DXMESH pMesh = g_Obj[obj].m_Mesh.GetLocalMesh();
  628.             UINT cPass;
  629.             V( g_pEffect->Begin( &cPass, 0 ) );
  630.             for( UINT p = 0; p < cPass; ++p )
  631.             {
  632.                 V( g_pEffect->BeginPass( p ) );
  633.  
  634.                 for( DWORD i = 0; i < g_Obj[obj].m_Mesh.m_dwNumMaterials; ++i )
  635.                 {
  636.                     D3DXVECTOR4 vDif( g_Obj[obj].m_Mesh.m_pMaterials[i].Diffuse.r,
  637.                                       g_Obj[obj].m_Mesh.m_pMaterials[i].Diffuse.g,
  638.                                       g_Obj[obj].m_Mesh.m_pMaterials[i].Diffuse.b,
  639.                                       g_Obj[obj].m_Mesh.m_pMaterials[i].Diffuse.a );
  640.                     V( g_pEffect->SetVector( "g_vMaterial", &vDif ) );
  641.                     if( g_Obj[obj].m_Mesh.m_pTextures[i] )
  642.                         V( g_pEffect->SetTexture( "g_txScene", g_Obj[obj].m_Mesh.m_pTextures[i] ) )
  643.                     else
  644.                         V( g_pEffect->SetTexture( "g_txScene", g_pTexDef ) )
  645.                     V( g_pEffect->CommitChanges() );
  646.                     V( pMesh->DrawSubset( i ) );
  647.                 }
  648.                 V( g_pEffect->EndPass() );
  649.             }
  650.             V( g_pEffect->End() );
  651.         }
  652.  
  653.         // Render light
  654.         if( !bRenderShadow )
  655.             V( g_pEffect->SetTechnique( "RenderLight" ) );
  656.  
  657.         D3DXMATRIXA16 mWorldView = *g_LCamera.GetWorldMatrix();
  658.         D3DXMatrixMultiply( &mWorldView, &mWorldView, pmView );
  659.         V( g_pEffect->SetMatrix( "g_mWorldView", &mWorldView ) );
  660.  
  661.         UINT cPass;
  662.         LPD3DXMESH pMesh = g_LightMesh.GetLocalMesh();
  663.         V( g_pEffect->Begin( &cPass, 0 ) );
  664.         for( UINT p = 0; p < cPass; ++p )
  665.         {
  666.             V( g_pEffect->BeginPass( p ) );
  667.  
  668.             for( DWORD i = 0; i < g_LightMesh.m_dwNumMaterials; ++i )
  669.             {                                     
  670.                 D3DXVECTOR4 vDif( g_LightMesh.m_pMaterials[i].Diffuse.r,
  671.                                   g_LightMesh.m_pMaterials[i].Diffuse.g,
  672.                                   g_LightMesh.m_pMaterials[i].Diffuse.b,
  673.                                   g_LightMesh.m_pMaterials[i].Diffuse.a );
  674.                 V( g_pEffect->SetVector( "g_vMaterial", &vDif ) );
  675.                 V( g_pEffect->SetTexture( "g_txScene", g_LightMesh.m_pTextures[i] ) );
  676.                 V( g_pEffect->CommitChanges() );
  677.                 V( pMesh->DrawSubset( i ) );
  678.             }
  679.             V( g_pEffect->EndPass() );
  680.         }
  681.         V( g_pEffect->End() );
  682.  
  683.         if( !bRenderShadow )
  684.             // Render stats and help text
  685.             RenderText();
  686.  
  687.         // Render the UI elements
  688.         if( !bRenderShadow )
  689.             g_HUD.OnRender( fElapsedTime );
  690.  
  691.         V( pd3dDevice->EndScene() );
  692.     }
  693. }
  694.  
  695.  
  696. //--------------------------------------------------------------------------------------
  697. // This callback function will be called at the end of every frame to perform all the 
  698. // rendering calls for the scene, and it will also be called if the window needs to be 
  699. // repainted. After this function has returned, the sample framework will call 
  700. // IDirect3DDevice9::Present to display the contents of the next buffer in the swap chain
  701. //--------------------------------------------------------------------------------------
  702. void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  703. {
  704.     HRESULT hr;
  705.  
  706.     //
  707.     // Compute the view matrix for the light
  708.     // This changes depending on the light mode
  709.     // (free movement or attached)
  710.     //
  711.     D3DXMATRIXA16 mLightView;
  712.     if( g_bFreeLight )
  713.         mLightView = *g_LCamera.GetViewMatrix();
  714.     else
  715.     {
  716.         // Light attached to car.
  717.         mLightView = g_Obj[2].m_mWorld;
  718.         D3DXVECTOR3 vPos( mLightView._41, mLightView._42, mLightView._43 );  // Offset z by -2 so that it's closer to headlight
  719.         D3DXVECTOR4 vDir = D3DXVECTOR4( 0.0f, 0.0f, -1.0f, 1.0f );  // In object space, car is facing -Z
  720.         mLightView._41 = mLightView._42 = mLightView._43 = 0.0f;  // Remove the translation
  721.         D3DXVec4Transform( &vDir, &vDir, &mLightView );  // Obtain direction in world space
  722.         vDir.w = 0.0f;  // Set w 0 so that the translation part below doesn't come to play
  723.         D3DXVec4Normalize( &vDir, &vDir );
  724.         vPos.x += vDir.x * 4.0f;  // Offset the center by 4 so that it's closer to the headlight
  725.         vPos.y += vDir.y * 4.0f;
  726.         vPos.z += vDir.z * 4.0f;
  727.         vDir.x += vPos.x;  // vDir denotes the look-at point
  728.         vDir.y += vPos.y;
  729.         vDir.z += vPos.z;
  730.         D3DXVECTOR3 vUp( 0.0f, 1.0f, 0.0f );
  731.         D3DXMatrixLookAtLH( &mLightView, &vPos, (D3DXVECTOR3*)&vDir, &vUp );
  732.     }
  733.  
  734.     //
  735.     // Render the shadow map
  736.     //
  737.     LPDIRECT3DSURFACE9 pOldRT = NULL;
  738.     V( pd3dDevice->GetRenderTarget( 0, &pOldRT ) );
  739.     LPDIRECT3DSURFACE9 pShadowSurf;
  740.     if( SUCCEEDED( g_pShadowMap->GetSurfaceLevel( 0, &pShadowSurf ) ) )
  741.     {
  742.         pd3dDevice->SetRenderTarget( 0, pShadowSurf );
  743.         SAFE_RELEASE( pShadowSurf );
  744.     }
  745.     LPDIRECT3DSURFACE9 pOldDS = NULL;
  746.     if( SUCCEEDED( pd3dDevice->GetDepthStencilSurface( &pOldDS ) ) )
  747.         pd3dDevice->SetDepthStencilSurface( g_pDSShadow );
  748.  
  749.     {
  750.         CDXUTPerfEventGenerator g( DXUT_PERFEVENTCOLOR, L"Shadow Map" );
  751.         RenderScene( pd3dDevice, true, fElapsedTime, &mLightView, &g_mShadowProj );
  752.     }
  753.  
  754.     if( pOldDS )
  755.     {
  756.         pd3dDevice->SetDepthStencilSurface( pOldDS );
  757.         pOldDS->Release();
  758.     }
  759.     pd3dDevice->SetRenderTarget( 0, pOldRT );
  760.     SAFE_RELEASE( pOldRT );
  761.  
  762.     //
  763.     // Now that we have the shadow map, render the scene.
  764.     //
  765.     const D3DXMATRIX *pmView = g_bCameraPerspective ? g_VCamera.GetViewMatrix() :
  766.                                                       &mLightView;
  767.  
  768.     // Initialize required parameter
  769.     V( g_pEffect->SetTexture( "g_txShadow", g_pShadowMap ) );
  770.     // Compute the matrix to transform from view space to
  771.     // light projection space.  This consists of
  772.     // the inverse of view matrix * view matrix of light * light projection matrix
  773.     D3DXMATRIXA16 mViewToLightProj;
  774.     mViewToLightProj = *pmView;
  775.     D3DXMatrixInverse( &mViewToLightProj, NULL, &mViewToLightProj );
  776.     D3DXMatrixMultiply( &mViewToLightProj, &mViewToLightProj, &mLightView );
  777.     D3DXMatrixMultiply( &mViewToLightProj, &mViewToLightProj, &g_mShadowProj );
  778.     V( g_pEffect->SetMatrix( "g_mViewToLightProj", &mViewToLightProj ) );
  779.  
  780.     {
  781.         CDXUTPerfEventGenerator g( DXUT_PERFEVENTCOLOR, L"Scene" );
  782.         RenderScene( pd3dDevice, false, fElapsedTime, pmView, g_VCamera.GetProjMatrix() );
  783.     }
  784.     g_pEffect->SetTexture( "g_txShadow", NULL );
  785. }
  786.  
  787.  
  788. //--------------------------------------------------------------------------------------
  789. // Render the help and statistics text. This function uses the ID3DXFont interface for 
  790. // efficient text rendering.
  791. //--------------------------------------------------------------------------------------
  792. void RenderText()
  793. {
  794.     // The helper object simply helps keep track of text position, and color
  795.     // and then it calls pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr );
  796.     // If NULL is passed in as the sprite object, then it will work however the 
  797.     // pFont->DrawText() will not be batched together.  Batching calls will improves performance.
  798.     CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 );
  799.  
  800.     // Output statistics
  801.     txtHelper.Begin();
  802.     txtHelper.SetInsertionPos( 5, 5 );
  803.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
  804.     txtHelper.DrawTextLine( DXUTGetFrameStats() );
  805.     txtHelper.DrawTextLine( DXUTGetDeviceStats() );
  806.  
  807.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  808.     
  809.     // Draw help
  810.     if( g_bShowHelp )
  811.     {
  812.         const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
  813.         txtHelper.SetInsertionPos( 10, pd3dsdBackBuffer->Height-15*10 );
  814.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.75f, 0.0f, 1.0f ) );
  815.         txtHelper.DrawTextLine( L"Controls:" );
  816.  
  817.         txtHelper.SetInsertionPos( 15, pd3dsdBackBuffer->Height-15*9 );
  818.         txtHelper.DrawFormattedTextLine(
  819.             L"Rotate camera\nMove camera\n"
  820.             L"Rotate light\nMove light\n"
  821.             L"Change light mode (Current: %s)\nChange view reference (Current: %s)\n"
  822.             L"Hidehelp\nQuit",
  823.             g_bFreeLight ? L"Free" : L"Car-attached",
  824.             g_bCameraPerspective ? L"Camera" : L"Light" );
  825.         txtHelper.SetInsertionPos( 265, pd3dsdBackBuffer->Height-15*9 );
  826.         txtHelper.DrawTextLine(
  827.             L"Left drag mouse\nW,S,A,D,Q,E\n"
  828.             L"Right drag mouse\nW,S,A,D,Q,E while holding right mouse\n"
  829.             L"F\nV\nF1\nESC" );
  830.     }
  831.     else
  832.     {
  833.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  834.         txtHelper.DrawTextLine( L"Press F1 for help" );
  835.     }
  836.     txtHelper.End();
  837. }
  838.  
  839.  
  840. //--------------------------------------------------------------------------------------
  841. // Before handling window messages, the sample framework passes incoming windows 
  842. // messages to the application through this callback function. If the application sets 
  843. // *pbNoFurtherProcessing to TRUE, then the sample framework will not process this message.
  844. //--------------------------------------------------------------------------------------
  845. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing )
  846. {
  847.     *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
  848.     if( *pbNoFurtherProcessing )
  849.         return 0;
  850.  
  851.     // Pass all windows messages to camera and dialogs so they can respond to user input
  852.     if( WM_KEYDOWN != uMsg || g_bRightMouseDown )
  853.         g_LCamera.HandleMessages( hWnd, uMsg, wParam, lParam );
  854.  
  855.     if( WM_KEYDOWN != uMsg || !g_bRightMouseDown )
  856.     {
  857.         if( g_bCameraPerspective )
  858.             g_VCamera.HandleMessages( hWnd, uMsg, wParam, lParam );
  859.         else
  860.             g_LCamera.HandleMessages( hWnd, uMsg, wParam, lParam );
  861.     }
  862.  
  863.     return 0;
  864. }
  865.  
  866.  
  867. //--------------------------------------------------------------------------------------
  868. // As a convenience, the sample framework inspects the incoming windows messages for
  869. // keystroke messages and decodes the message parameters to pass relevant keyboard
  870. // messages to the application.  The framework does not remove the underlying keystroke 
  871. // messages, which are still passed to the application's MsgProc callback.
  872. //--------------------------------------------------------------------------------------
  873. void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown )
  874. {
  875. }
  876.  
  877.  
  878. void CALLBACK MouseProc( bool bLeftButtonDown, bool bRightButtonDown, bool bMiddleButtonDown, bool bSideButton1Down, bool bSideButton2Down, int nMouseWheelDelta, int xPos, int yPos )
  879. {
  880.     g_bRightMouseDown = bRightButtonDown;
  881. }
  882.  
  883.  
  884. //--------------------------------------------------------------------------------------
  885. // Handles the GUI events
  886. //--------------------------------------------------------------------------------------
  887. void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl )
  888. {
  889.     switch( nControlID )
  890.     {
  891.         case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break;
  892.         case IDC_TOGGLEREF:        DXUTToggleREF(); break;
  893.         case IDC_CHANGEDEVICE:     DXUTSetShowSettingsDialog( !DXUTGetShowSettingsDialog() ); break;
  894.         case IDC_CHECKBOX:
  895.         {
  896.             CDXUTCheckBox *pCheck = (CDXUTCheckBox *)pControl;
  897.             g_bShowHelp = pCheck->GetChecked();
  898.             break;
  899.         }
  900.         case IDC_LIGHTPERSPECTIVE:
  901.         {
  902.             CDXUTCheckBox *pCheck = (CDXUTCheckBox *)pControl;
  903.             g_bCameraPerspective = !pCheck->GetChecked();
  904.             if( g_bCameraPerspective )
  905.             {
  906.                 g_VCamera.SetRotateButtons( true, false, false );
  907.                 g_LCamera.SetRotateButtons( false, false, true );
  908.             } else
  909.             {
  910.                 g_VCamera.SetRotateButtons( false, false, false );
  911.                 g_LCamera.SetRotateButtons( true, false, true );
  912.             }
  913.  
  914.             break;
  915.         }
  916.         case IDC_ATTACHLIGHTTOCAR:
  917.         {
  918.             CDXUTCheckBox *pCheck = (CDXUTCheckBox *)pControl;
  919.             g_bFreeLight = !pCheck->GetChecked();
  920.             break;
  921.         }
  922.     }
  923. }
  924.  
  925.  
  926. //--------------------------------------------------------------------------------------
  927. // This callback function will be called immediately after the Direct3D device has 
  928. // entered a lost state and before IDirect3DDevice9::Reset is called. Resources created
  929. // in the OnResetDevice callback should be released here, which generally includes all 
  930. // D3DPOOL_DEFAULT resources. See the "Lost Devices" section of the documentation for 
  931. // information about lost devices.
  932. //--------------------------------------------------------------------------------------
  933. void CALLBACK OnLostDevice()
  934. {
  935.     if( g_pFont )
  936.         g_pFont->OnLostDevice();
  937.     if( g_pFontSmall )
  938.         g_pFontSmall->OnLostDevice();
  939.     if( g_pEffect )
  940.         g_pEffect->OnLostDevice();
  941.     SAFE_RELEASE(g_pTextSprite);
  942.  
  943.     SAFE_RELEASE( g_pDSShadow );
  944.     SAFE_RELEASE( g_pShadowMap );
  945.     SAFE_RELEASE( g_pTexDef );
  946.  
  947.     for( int i = 0; i < NUM_OBJ; ++i )
  948.         g_Obj[i].m_Mesh.InvalidateDeviceObjects();
  949.     g_LightMesh.InvalidateDeviceObjects();
  950. }
  951.  
  952.  
  953. //--------------------------------------------------------------------------------------
  954. // This callback function will be called immediately after the Direct3D device has 
  955. // been destroyed, which generally happens as a result of application termination or 
  956. // windowed/full screen toggles. Resources created in the OnCreateDevice callback 
  957. // should be released here, which generally includes all D3DPOOL_MANAGED resources. 
  958. //--------------------------------------------------------------------------------------
  959. void CALLBACK OnDestroyDevice()
  960. {
  961.     SAFE_RELEASE( g_pEffect );
  962.     SAFE_RELEASE( g_pFont );
  963.     SAFE_RELEASE( g_pFontSmall );
  964.     SAFE_RELEASE( g_pVertDecl );
  965.  
  966.     SAFE_RELEASE( g_pEffect );
  967.  
  968.     for( int i = 0; i < NUM_OBJ; ++i )
  969.         g_Obj[i].m_Mesh.Destroy();
  970.     g_LightMesh.Destroy();
  971. }
  972.